package com.compomics.proteocloud.ui;


import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.ConnectException;
import java.sql.SQLException;
import java.util.Properties;
import java.util.List;

import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.compomics.proteocloud.db.accessor.Project;
import com.compomics.proteocloud.db.accessor.Taxon;
import com.compomics.proteocloud.starter.CloudTools;
import com.compomics.proteocloud.util.AWSUtils;
import com.compomics.util.gui.JLabelAndComponentPanel;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import org.jets3t.service.model.S3Bucket;

/**
 * The ProjectSettingsDialog which is displayed at the application startup and for the various settings.
 *
 * @author Thilo Muth
 * @date 29/08/2012
 */
public class ProjectSettingsDialog extends JDialog {
	
	private JTextField txtDatabase;
    private JTextField txtKeyPair;
    private JTextField txtGroup;
    private JTextField txtAccessKey;
    private JPasswordField txtSecretKey;
	private ProteoCloudUI parent;
	private JTextField txtDbUser;
	private JPasswordField txtDbPass;
	private JTextField txtDbName;  
    private JTabbedPane tabbedPane;
    private JPanel openProjectPnl;
    private CellConstraints cc;
    private JTextField selectedProjectTtf;
    private JPanel dbSettingsPnl;
    private JPanel credentialsPnl;
    private JButton openProjectBtn;
    private int selectedTabIndex;
    private JPanel projectPnl;
    private JTextField projectNameTtf;
    private JComboBox taxaCbx;
    private CloudTools cloudTools = CloudTools.getInstance();
    private JButton createBtn;
    private JTextField fragIonTolTtf;
    private JTextField precIonTolTtf;
    private JComboBox precUnitCbx;
    private JPanel s3BucketPnl;
    private JTextField selectedBucketTtf;

    /**
     * Default constructor with the first tab selected by default.
     * @param parent Parent frame.
     * @param modal Modal dialog state.
     */
    private ProjectSettingsDialog(ProteoCloudUI parent, boolean modal) {
        this(parent, modal, 0);
    }

    /**
     * This constructor allows for the selection of a specific tab in the dialog.
     *
     * @param parent Parent frame.
     * @param modal Modal dialog state.
     * @param selectedTabIndex The index of the preselected tab in the dialog.
     */
    private ProjectSettingsDialog(ProteoCloudUI parent, boolean modal, int selectedTabIndex) {
        super(parent, "ProteoCloud Settings", modal);
        this.parent = parent;
        this.selectedTabIndex = selectedTabIndex;
        initComponents();
        setPreferredSize(new Dimension(480, 300));
        pack();
        setResizable(false);
        setLocationRelativeTo(parent);
        this.addWindowListener(new WindowAdapter() {    
            public void windowClosing(WindowEvent e) {
                close();
            }
        });
        setVisible(true);
    }

    /**
     * Factory method which constructs the default ProjectSettingsDialog.
     * @param parent Parent frame.
     * @param modal Modal dialog state.
     * @return The ProjectSettingsDialog.
     */
    public static ProjectSettingsDialog createProjectSettingsDialog(ProteoCloudUI parent, boolean modal) {
        return new ProjectSettingsDialog(parent, modal);
    }

    /**
     * Factory method with pre-selection of a specific tab in the dialog.
     * @param parent Parent frame.
     * @param modal Modal dialog state.
     * @param selectedTabIndex The index of the preselected tab in the dialog.
     * @return The ProjectSettingsDialog.
     */
    public static ProjectSettingsDialog createProjectSettingsDialog(ProteoCloudUI parent, boolean modal, int selectedTabIndex) {
        return new ProjectSettingsDialog(parent, modal, selectedTabIndex);
    }

    /**
     * Initializes the components.
     */
    private void initComponents() {
        cc = new CellConstraints();
        Container cp = this.getContentPane();
        cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
        createOpenProjectPanel();
        createNewProjectPanel();
        createAWSCredentialsPanel();
        createDatabaseSettingsPanel();
        createS3BucketPanel();
        tabbedPane = new JTabbedPane();
        tabbedPane.addTab("Open Project", openProjectPnl);
        tabbedPane.addTab("New Project", projectPnl);
        tabbedPane.addTab("AWS Credentials", credentialsPnl);
        tabbedPane.addTab("Database Settings", dbSettingsPnl);
        tabbedPane.addTab("S3 Buckets", s3BucketPnl);
        cp.add(Box.createVerticalStrut(10));
        cp.add(tabbedPane);

        // Tab selection
        tabbedPane.setSelectedIndex(selectedTabIndex);
    }
    
    private void createOpenProjectPanel() {
        openProjectPnl = new JPanel(new FormLayout("5dlu, p, 5dlu, p, 5dlu", "5dlu, t:p, 5dlu"));
        openProjectPnl.setBorder(BorderFactory.createTitledBorder("Project Selection"));
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setPreferredSize(new Dimension(200, 150));
        scrollPane.setHorizontalScrollBar(null);
        String[] projects = new String[0];
        try {
            projects = CloudTools.getInstance().getProjects();
        } catch (ConnectException e) {
            JOptionPane.showMessageDialog(this, e.getMessage(), "Please provide valid database settings.", JOptionPane.ERROR_MESSAGE);
        }
        final JList projectLst = new JList(projects);
        projectLst.setPreferredSize(new Dimension(200, projectLst.getHeight()));
        projectLst.setBackground(Color.WHITE);
        projectLst.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
        scrollPane.setViewportView(projectLst);
        openProjectPnl.add(scrollPane, cc.xy(2, 2));

        JLabel selectedProjectLbl = new JLabel("Selected Project: ");

        selectedProjectTtf = new JTextField(15);


        projectLst.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    selectedProjectTtf.setText(projectLst.getSelectedValue().toString());
                }
            }
        });
        if(projects != null && projects.length > 0) {
            projectLst.setSelectedIndex(0);
        }

        openProjectBtn = new JButton("Open");
        openProjectBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                openProjectBtnTriggered();
            }
        });

        JPanel selectionPnl = new JPanel(new FormLayout("5dlu, p, 5dlu", "p, 5dlu, p, 5dlu, p, 5dlu"));
        selectionPnl.add(selectedProjectLbl, cc.xy(2, 1));
        selectionPnl.add(selectedProjectTtf, cc.xy(2, 3));
        selectionPnl.add(openProjectBtn, cc.xy(2, 5));
        openProjectPnl.add(selectionPnl, cc.xy(4, 2));
    }

    /**
     * This method initializes the new project panel.
     */
    private void createNewProjectPanel() {
        projectPnl = new JPanel(new FormLayout("5dlu, p, 5dlu, p, 10dlu, p, 5dlu", "5dlu, p, 5dlu, p, 5dlu,  p, 5dlu, p, 5dlu, p, 5dlu, p, 5dlu"));
        projectPnl.setBorder(BorderFactory.createTitledBorder("Project Settings"));
        JLabel projectNameLbl = new JLabel("Project Name:");
        projectNameTtf = new JTextField(12);

        JLabel taxonLbl = new JLabel("Database:");

        try {
            List<Taxon> taxonList = cloudTools.retrieveAllTaxa();
            String[] taxa = new String[0];
            if(taxonList != null){
                taxa = new String[taxonList.size()];
                for(int i = 0; i < taxonList.size(); i++) {
                    taxa[i] = taxonList.get(i).getSpecies();
                }
            }
            taxaCbx = new JComboBox(taxa);
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, e.getMessage(), "Database error", JOptionPane.ERROR_MESSAGE);
        }

        JLabel fragIonTolLbl = new JLabel("Fragment Ion Tolerance:");
        JLabel precIonTolLbl = new JLabel("Precursor Ion Tolerance:");
        JLabel precUnitLbl = new JLabel("Precursor Unit:");

        fragIonTolTtf = new JTextField(12);
        precIonTolTtf = new JTextField(12);
        precUnitCbx = new JComboBox(new String[]{"Da", "PPM"});
        createBtn = new JButton("Create Project");
        createBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                createBtnTriggered();
            }
        });

        projectPnl.add(projectNameLbl, cc.xy(2, 2));
        projectPnl.add(projectNameTtf, cc.xy(4, 2));
        projectPnl.add(taxonLbl, cc.xy(2, 4));
        projectPnl.add(taxaCbx, cc.xy(4, 4));
        projectPnl.add(fragIonTolLbl, cc.xy(2, 6));
        projectPnl.add(fragIonTolTtf, cc.xy(4, 6));
        projectPnl.add(precIonTolLbl, cc.xy(2, 8));
        projectPnl.add(precIonTolTtf, cc.xy(4, 8));
        projectPnl.add(precUnitLbl, cc.xy(2, 10));
        projectPnl.add(precUnitCbx, cc.xy(4, 10));
        projectPnl.add(createBtn, cc.xy(6, 10));
    }

    /**
     * Creates the S3 Bucket panel.
     */
    private void createS3BucketPanel() {
        s3BucketPnl = new JPanel(new FormLayout("5dlu, p, 5dlu, p, 5dlu", "5dlu, t:p, 5dlu"));
        s3BucketPnl.setBorder(BorderFactory.createTitledBorder("Bucket Selection"));
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setPreferredSize(new Dimension(200, 150));
        scrollPane.setHorizontalScrollBar(null);
        
        // Activate vertical scroll bar.
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        
        String[] names = new String[0];
        S3Bucket[] s3Buckets = CloudTools.getInstance().listBuckets();
        if(s3Buckets != null && s3Buckets.length > 0){
            names = new String[s3Buckets.length];
            for (int i = 0; i < s3Buckets.length; i++) {
                names[i] = s3Buckets[i].getName();
            }
        }

        final JList bucketLst = new JList(names);
        //bucketLst.setPreferredSize(new Dimension(200, bucketLst.getHeight()));
        bucketLst.setBackground(Color.WHITE);
        bucketLst.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        scrollPane.setViewportView(bucketLst);
        s3BucketPnl.add(scrollPane, cc.xy(2, 2));
        JLabel selectedBucketLbl = new JLabel("Selected Bucket: ");
        selectedBucketTtf = new JTextField(15);

        bucketLst.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    String selectedBucket = bucketLst.getSelectedValue().toString();
                    selectedBucketTtf.setText(selectedBucket);
                    CloudTools.getProperties().setProperty(AWSUtils.BUCKET, selectedBucket);
                }
            }
        });

        if(names.length > 0) {
            bucketLst.setSelectedIndex(0);
        }

        JPanel selectionPnl = new JPanel(new FormLayout("5dlu, p, 5dlu", "p, 5dlu, p, 5dlu, p, 5dlu"));
        selectionPnl.add(selectedBucketLbl, cc.xy(2, 1));
        selectionPnl.add(selectedBucketTtf, cc.xy(2, 3));
        s3BucketPnl.add(selectionPnl, cc.xy(4, 2));
    }

    /**
     * This method is executed when the create button is triggered.
     */
    private void createBtnTriggered() {
        String dbUrl = txtDatabase.getText().trim();
        if (dbUrl == null || dbUrl.equals("")) {
            this.fillOutComponentWarning("Db Url");
            txtDatabase.requestFocus();
            return;
        }
        String dbUser = txtDbUser.getText().trim();
        if (dbUser == null || dbUser.equals("")) {
            this.fillOutComponentWarning("Db User");
            txtDbUser.requestFocus();
            return;
        }
        String dbPass = String.valueOf(txtDbPass.getPassword());
        if (dbPass == null || dbPass.equals("")) {
            this.fillOutComponentWarning("Db Password");
            txtDbPass.requestFocus();
            return;
        }
        String dbName = txtDbName.getText().trim();
        if (dbName == null || dbName.equals("")) {
            this.fillOutComponentWarning("Db Name");
            txtDbName.requestFocus();
            return;
        }

        String projectTitle = projectNameTtf.getText().trim();
        if (projectTitle == null || projectTitle.equals("")) {
            this.fillOutComponentWarning("Project Name");
            projectNameTtf.requestFocus();
            return;
        }

        String taxonTitle = taxaCbx.getSelectedItem().toString();
        if (taxonTitle == null || taxonTitle.equals("")) {
            this.fillOutComponentWarning("Taxon Database");
            taxaCbx.requestFocus();
            return;
        }

        String fragIonTol = fragIonTolTtf.getText().trim();
        if (fragIonTol == null || fragIonTol.equals("")) {
            this.fillOutComponentWarning("Fragment Ion Tolerance");
            fragIonTolTtf.requestFocus();
            return;
        }

        String precIonTol = precIonTolTtf.getText().trim();
        if (precIonTol == null || precIonTol.equals("")) {
            this.fillOutComponentWarning("Precursor Ion Tolerance");
            precIonTolTtf.requestFocus();
            return;
        }

        try {
            cloudTools.createNewProject(projectTitle, taxonTitle, fragIonTol, precIonTol, precUnitCbx.getSelectedItem().toString());
            parent.setProjectSettings(dbUrl, dbUser, dbPass, dbName, projectTitle, taxonTitle, precUnitCbx.getSelectedItem().toString(), precIonTol, fragIonTol);
            close();
        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, e.getMessage(), "Database error", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * This method initializes the AWS Credentials panel.
     */
    private void createAWSCredentialsPanel() {
        // Next on the list are the DB components.
        credentialsPnl = new JPanel(new FormLayout("5dlu, p, 5dlu", "5dlu, p, 5dlu"));
        credentialsPnl.setBorder(BorderFactory.createTitledBorder("AWS Credentials"));

        txtKeyPair = new JTextField(25);
        txtGroup = new JTextField(25);
        txtAccessKey = new JTextField(25);
        txtSecretKey = new JPasswordField(25);
        setDefaultAWSCredentialsValues();

        final JLabelAndComponentPanel jpanLT = new JLabelAndComponentPanel(new JLabel[]{new JLabel("Key Pair"), new JLabel("Security Group"), new JLabel("Access Key"), new JLabel("Secret Key")}, new JTextField[]{txtKeyPair, txtGroup, txtAccessKey, txtSecretKey});
        credentialsPnl.add(jpanLT, cc.xy(2, 2));
    }

	/**
     * This method initializes the database settings panel.
     */
    private void createDatabaseSettingsPanel() {
        // Next on the list are the DB components.
        dbSettingsPnl = new JPanel(new FormLayout("5dlu, p, 5dlu", "5dlu, p, 5dlu"));
        dbSettingsPnl.setBorder(BorderFactory.createTitledBorder("SQL Connection Settings"));
        txtDatabase = new JTextField(17);
        txtDbUser = new JTextField(17);
        txtDbPass = new JPasswordField(17);
        txtDbName = new JTextField(17);
        setDefaultDbSettingsValues();
        final JLabelAndComponentPanel jpanLT = new JLabelAndComponentPanel(new JLabel[]{new JLabel("Db Url"), new JLabel("Db User"), new JLabel("Db Password"), new JLabel("Db Name")}, new JComponent[]{txtDatabase, txtDbUser, txtDbPass, txtDbName});
        dbSettingsPnl.add(jpanLT, cc.xy(2, 2));
    }

    /**
     * This method sets the default values for the AWS Credentials values.
     */
    private void setDefaultAWSCredentialsValues() {
        // Get the properties object
        Properties props = AWSUtils.getProperties();
        txtKeyPair.setText(props.getProperty(AWSUtils.DEFAULT_KEYPAIR));
        txtGroup.setText(props.getProperty(AWSUtils.DEFAULT_SECURITY_GROUP));
        txtAccessKey.setText(props.getProperty(AWSUtils.AWS_ACCESS_KEY_PROPERTY_NAME));
        txtSecretKey.setText(props.getProperty(AWSUtils.AWS_SECRET_KEY_PROPERTY_NAME));
    }

    /**
     * This method sets the default values for the project settings.
     */
    private void setDefaultDbSettingsValues() {
    	// Get the properties object     
    	Properties props = AWSUtils.getProperties();
    	txtDatabase.setText(props.getProperty(AWSUtils.DATABASE_URL));
    	txtDbUser.setText(props.getProperty(AWSUtils.DATABASE_USER));
    	txtDbPass.setText(props.getProperty(AWSUtils.DATABASE_PASS));
        txtDbName.setText(props.getProperty(AWSUtils.DATABASE_NAME));
        precIonTolTtf.setText(props.getProperty(AWSUtils.PREC_IONTOL));
        fragIonTolTtf.setText(props.getProperty(AWSUtils.FRAG_IONTOL));
    }


    /**
     * This method is called when the 'Cancel' button is pressed.
     */
    private void cancelPressed() {
        this.close();
    }
    
    /**
     * This method closes the window without any other action.
     */
    private void close() {
        this.setVisible(false);
        this.dispose();
        // Refresh the storage table only if credentials are provided.
        if(cloudTools.areCredentialsProvided()) parent.refreshStorageTable();
    }

    /**
     * Called when the open project button is triggered.
     */
    private void openProjectBtnTriggered() {
        String dbUrl = txtDatabase.getText().trim();
        if (dbUrl == null || dbUrl.equals("")) {
            this.fillOutComponentWarning("Db Url");
            txtDatabase.requestFocus();
            return;
        }
        String dbUser = txtDbUser.getText().trim();
        if (dbUser == null || dbUser.equals("")) {
            this.fillOutComponentWarning("Db User");
            txtDbUser.requestFocus();
            return;
        }
        String dbPass = String.valueOf(txtDbPass.getPassword());
        if (dbPass == null || dbPass.equals("")) {
            this.fillOutComponentWarning("Db Password");
            txtDbPass.requestFocus();
            return;
        }
        String dbName = txtDbName.getText().trim();
        if (dbName == null || dbName.equals("")) {
            this.fillOutComponentWarning("Db Name");
            txtDbName.requestFocus();
            return;
        }

        String projectTitle = selectedProjectTtf.getText().trim();
        if (projectTitle == null || projectTitle.equals("")) {
            this.fillOutComponentWarning("Selected Project");
            selectedProjectTtf.requestFocus();
            return;
        }
        Project project = null;
        try {
            project = cloudTools.getProjectByTitle(projectTitle);
        } catch (ConnectException e) {
            JOptionPane.showMessageDialog(this, e.getMessage(), "Please provide valid database settings.", JOptionPane.ERROR_MESSAGE);
        }
        parent.setProjectSettings(dbUrl, dbUser, dbPass, dbName, projectTitle, project.getTaxon(), project.getPrecursor_unit(), project.getPrecursor_tol().toString(), project.getFragment_tol().toString());

        // Get the results
        parent.getResults(projectTitle);
        close();
    }

    /**
     * This method displays an error message about the necessity of filling out the specified component first.
     *
     * @param aComponent String with the description of the data for the component that needs to be filled out.
     */
    private void fillOutComponentWarning(String aComponent) {
        String lMessage = "You need to fill out the " + aComponent + " first!";
        JOptionPane.showMessageDialog(this, lMessage, aComponent + " not filled out!", JOptionPane.ERROR_MESSAGE);
    }
}
